--- %%NOBANNER%% -->
![]() | ![]() |
/*------------------<--- Start of Description -->--------------------\ | This macro will calculate the general survival statistics (p(t), | | standard error, confidience limits, and median survival time, for | | the following special cases: | | 1) Left-truncated survival; | | 2) Time dependant calculations where a person can change state | | (CLASS) after time zero. | | This macro does not do any testing. Use Procedures phreg, cox, etc.| | This macro, also, does not support multiple event data. | |--------------------<--- End of Description -->---------------------| |--------------------------------------------------------------------| |--------------<--- Start of Files or Arguments Needed -->-----------| | The Input Parameters are: | | STRTTIME = Variable containing the beginning time. See examples | | above. (Required). | | STOPTIME = Variable containing the ending time. See examples | | above. (Required) | | EVENT = Variable containing the event status at STOPTIME, as a | | numeric two-valued variable, | | (0,1), (1,2) etc. The event value must be 1 larger | | than the censoring value. (Required), | | CEN_VL = Censoring value for the EVENT variable as 0,1 etc. | | Event = Cen_vl + 1. (Default is 0) | | CLASS = Classification or state variable(s). They may be either | | character or numeric. Note - Any observations in the | | input dataset with missing CLASS data, are not included| | in the results. | | MINTIME = the beginning time for the suvival calculations and | | x-axis of the graph (Defualt is 0). Indicate MANTIME in| | the same units as STRTTIME, even if XDIVISOR is coded. | | BY = List of "by" variables. They may be either character or | | numeric. | | OUT = Output dataset name (Default is _SURVOUT) | | OUTSUM = Output summary dataset name (Default is _SURVSUM) | | DATA = Input dataset name (Default is the last dataset created) | | PRINTOP = printing options (Default is 1): | | 0 = print nothing | | 1 = print summary table only | | 2 = print one line per event | | 3 = print one line per event, arrival, and/or censor | | 4 = print one line for each of a series of time points,| | as months, half-years, or years (see POINTS) | | 5 = print one line per event and/or defined time points| | 6 = print one line per event,arrival, censor, and/or | | time point. | | POINTS = Specific time points at which survival statistics are | | needed, as months, half-years, years. These points are | | specified by dividing time into intervals as: | | '0 to 36500 by 365'. | | The endpoint of each interval will be the time point to | | be reported. If you have comas within your statement, | | enclose the entire parameter in quotes, as: | | '0 to 360 by 30, 0 to 3650 by 182.5' | | You may also specify specific points as well as | | groups of points as: | | '1,5,10,15,0 to 36500 by 182.5' | | CL = Type of confidence limits (Default is 3) | | 1 = Greenwood (actual) | | 2 = Greenwood with modified lower limit | | 3 = log-e transformation (log) | | 4 = log-e transformation with modified lower limit | | 5 = log(-log-e) transformation (log(-log)) | | 6 = log(log-e) transformation with modified lower limit| | 7 = logit transformation (logit) | | 8 =logit transformation with modified lowere limit | | ALPHA= Type I error rate for confidence limits (Default is .05) | | MEDTYPE = Type of median if there are several time points | | having probability=.5 (Default is 1) | | 1 = use the midpoint between the times as the median | | 2 = use the first time value as the median | | PLOTTYPE = Where to plot the graph(s) (Default is 1) | | 1 = no plot | | 2 = greenbar printer plot | | 3 = graphics plot on unix laser printer | | 4 = plot goes to graphics window | | PLOTOP = What to plot on the y-axis (Default is 1) | | 1 = plot pt | | 2 = plot 1-pt or pe | | SCALE = plotting scale (Default is 1) | | 1 = arithmetic | | 2 = 1-cycle log | | 3 = 2-cycle log | | MAXTIME = the maximun time allowed for the x-axis (Default is the| | max time for all graphs per page). Specify MAXTIME in | | the same units as STRTTIME, even if XDIVISOR used. | | XDIVISOR = the divisor used if you want the plotted x-axis in | | other units then TIME is in. | | Example: XDIVISOR=365 would plot the x-axis as TIME/365. | | LASERPRT = the name of the HSR printer you want your plot to go | | to if different from your standard printer. | | Output Dataset OUT: | | Output Dataset (OUT) contains one observation for each event, | | censor, arrival, and extra time point specified by POINTS. | | The variables in the output dataset are: | | &by = the by-variable(s) (if defined); | | &class = the class variable(s) (if defined); | | &stoptime = the stoptime variable; | | NRISK = the number at risk at &stoptime; | | NEVENT = the number of events from &stoptime the next stoptime | | NCENSOR = the number of censors from &stoptime the next stoptime | | NARRIVE = the number of arrivals during this time; | | CUM_EV = the cumulative number of events up to and including | | &stoptime; | | CUM_CEN = The cumulative number of censors up to and including | | &stoptime; | | CUM_ARR = The cumulative number of arrivals up to and including | | this time; | | PT = The probability of no event up to and including &stoptime. | | PE = 1-PT, or the probability of an event occcurring; | | UPPER_CL = the upper confidience limit (based on the input | | parameters ALPHA and CL); | | LOWER_CL = the lower confidience limit (based on the input | | parameters ALPHA and CL); | | SE = the Greenwood Standard Error; | | POINTFLG = the flag indicating points added to the output dataset| | because the of POINTS option. (1=point added, | | missing otherwise); | | Output Dataset OUTSUM: | | Output Summary Dataset (OUTSUM) contains one observation for | | each group processed. That is, the total group, or each BY | | and/or CLASS value. The variables in the output dataset are: | | &by = the by-variable(s) (if defined); | | &class = the class variable(s) (if defined); | | TOTAL = the total number of observations in this group; | | CUM_EV = the total number of events in this group; | | CUM_CEN = the total number of censors in this group; | | CUM_ARR = the total number of arrivals in this group; | | TL_MISS = the total number of observations not included because | | of missing values; | | MEDIAN = the median survival time (based on the input parameter | | MEDTYPE); | | The following variables will be added if the LOGRANK test is | | specified: | | OBSERVED = the calculated number of observed events; | | EXPECTED = the calculated number of expected events; | | RR = the Relative Risk (this group's observed/expected / group | | 1's observed/expected); | | CHISQ = chi-square value; | | DF = degrees of freedom; | | PVALUE = pvalue (probability of a greater chi-square value); | | Notes: | | 1. If you are getting a message about VPOS not being large | | enough, try cutting down on the number of title lines you are | | using. SAS does it's calculations for size based on 1 title, | | so having 3 or 4 titles MAY cause a problem with the vertical | | spacing. | | 2. If you are plotting the output dataset yourself, remember that| | you need a symbol statement as follows to get the steps | | correct: | | symbol1 i=stepjl v=none l=1; | |---------------<--- End of Files or Arguments Needed -->------------| |--------------------------------------------------------------------| |----------------<--- Start of Example and Usage -->-----------------| | Left-truncation: | | An example of left-truncation is a study where surivial needs | | to be measured from initial diagnosis until death and there are | | several patients in the study diagnosed elsewhere prior to coming| | to Mayo. Patients diagnosed at Mayo contribute to the survival | | curve from date of diagnosis (t(0)), but those "arriving" at Mayo| | years (t(a)) after diagnosis contribute to the curve starting | | after time t(a). | | This macro will produce a survival curve using patients in | | the curve from the time they "arrive" until last | | follow-up. To do this you need a dataset with one observation | | per person with the following variables: | | STRTTIME = Variable containing the time (in any units) when | | the patient "arrives" measured from the time of | | initial interest (as initial diagnosis date in the | | above examp) If the patient "arrives" at time t(0) | | (the patient was diagnosed in Rochester) STRTTIME | | would be 0. | | STOPTIME = Variable containing the follow-up time measured from | | the time of initial interest (as initial diagnosis | | date in the above example). | | *** Note - STRTTIME and STOPTIME cannot be the same value. In | | some cases you may need to add a small value (0.5) | | to either the strttime or stoptime values to make | | them different. | | EVENT = variable containing the survival status at STOPTIME. | | | | Example: A person diagnosed in Rochester then dying on day 35: | | STRTTIME=0, STOPTIME=35, EVENT=1 | | Example: A person diagnosed elsewhere, coming to Rochester on | | day 35 then dying on day 200: | | STRTTIME=35, STOPTIME=200, EVENT=1 | | Example: A person diagnosed in Rochester then dying soon after: | | STRTTIME=0.1, STOPTIME=0.9, EVENT=1 | | Time Dependent Co-variates: | | An example of a time dependent covariate is a study where a | | patient was in one state (CLASS) for a length of time (as without a| | transplant), then moves into another state (CLASS) (as transplant).| | Survival is measured from some initial time (as date placed on the | | waiting list for a transplant) until last follow-up or death. | | This macro will produce a survival curve for each state of the | | time-dependent covariate (CLASS) (one for no transplant,and one for| | transplants, in the above example). Patients may, or may not, be in| | more than one of the curves, but they can only be in 1 curve at any| | given time (day, or day, hour and minute). Any person transferring| | from one state to another would have two observations, one for time| | in state 1 and another for the time in state 2. The EVENT variable| | would always be censored in the first observation. | | There is no limit to the number of transfers a patient can make. | | | | To do this you need a dataset with one observation per | | person per "state" with the following variables: | | CLASS = Variable containing the state or value of the | | covariate from STRTTIME to STOPTIME. In the above example | | CLASS will have 2 values, 0=no transplant and | | 1=transplanted. | | STRTTIME = Variable containing the starting time (in any units) | | for the patient in this state. If the patient is in | | this state at t(0) (date put on the transplant list) | | STRTTIME would be 0. | | STOPTIME = Variable containing the ending time (in any units) | | for the patient in this state. If the patient dies, or | | is censored this would be the last follow-up time. | | *** Note - STRTTIME and STOPTIME cannot be the same value. | | In some cases you may need to add a small value | | (0.5) to either the strttime or stoptime values to make | | them different. | | EVENT = variable containing the survival status at STOPTIME. | | EXample: A person on the transplant and never receive a transplant | | and dying on day 35 would have one observation with: | | CLASS=0, STRTTIME=0, STOPTIME=35, EVENT=1 | | Example: A person on the transplant list, transplanted on day 15, | | an dying on day 45 would have two observations, one for | | each class or state: | | CLASS=0, STRTTIME=0, STOPTIME=15, EVENT=0 | | CLASS=1, STRTTIME=15.5, STOPTIME=45, EVENT=1 | | Note: For both types of analysis, events occurring at t(0) should | | be recorded as STRTTIME=0.1 STOPTIME=0.9. | | Note: For both types of analysis, use the MINTIME variable to begin| | your survival calculations at some time later than t(0). This| | may be necessary if you have small numbers of people at risk | | in the first units of time. | | Examples: | | %survtd(strttime=roch_dt, stoptime=fu_time, event=fu_stat, | | cen_vl=1); | | %survtd(strttime=arrtime,stoptime=fu_time,event=fu_stat,cen_vl=1,| | out=two,data=one,printop=4,cl=6, mintime=30, | | points='0 to 36500 by 182.5'); | | %survtd(strttime=arrtime,stoptime=fu_time,event=fu_stat,cen_vl=1,| | class=chf,out=two,data=one,printop=4,cl=6, | | points='0 to 36500 by 182.5'); | | Usage: %SURVTD(STRTTIME= ,STOPTIME= ,EVENT= ,CEN_VL=0, PRINTOP=1, | | CLASS= ,BY= , MINTIME=0, DATA=&syslast,POINTS= , | | OUT=_SURVOUT,CL=3,ALPHA=.05,PLOTTYPE=1,PLOTOP=1, | | SCALE=1,MAXTIME=, XDIVISOR= ,LASERPRT= ,MEDTYPE=1, | | OUTSUM=_SURVSUM); | \-------------------<--- End of Example and Usage -->---------------*/ %MACRO SURVTD (STRTTIME= ,STOPTIME= ,EVENT= ,CEN_VL=0, PRINTOP=1, CLASS= ,BY= , MINTIME=0, DATA=&syslast, OUT=_SURVOUT,POINTS= ,CL=3, ALPHA=.05,PLOTTYPE=1,PLOTOP=1,SCALE=1,MAXTIME= , XDIVISOR= ,LASERPRT= ,MEDTYPE=1,OUTSUM=_SURVSUM); /*--------------------------------------------\ | Author: Jan Offord; | | Purpose: calculate the general survival | | statistics for left truncated data;| \--------------------------------------------*/ RUN; proc sql; reset noprint; select max(number) into :t from dictionary.titles; quit; %let t=%eval(&t+2); %if &t > 9 %then %let t=9; %let u=%eval(&t+1); %local byword byclword lastby lastbycl dev errorflg j a b x cgrp cl_name indata; %LET errorflg = 0; %LET byword = ; %LET byclword = ; %LET lastby = ; %LET lastbycl = ; %LET dev = &SYSDEVIC; %let a = %index(&points,%str(%')); %if &a > 0 %then %do; %let b = %eval(%length(&points)-1); %let points = %substr(&points,%eval(&a+1),%eval(&b-1)); %end; %if &strttime= %then %do; %put ERROR - Variablenot defined; %LET errorflg = 1; %end; %if &stoptime= %then %do; %put ERROR - Variable not defined; %LET errorflg = 1; %end; %if &event= %then %do; %put ERROR - Variable not defined; %LET errorflg = 1; %end; %if &cen_vl ^= 0 and &cen_vl ^= 1 %then %do; %put ERROR - Variable not defined as 0 or 1; %LET errorflg = 1; %end; %if &printop < 0 or &printop > 6 %then %do; %put ERROR - Variable not defined as 0-6; %LET errorflg = 1; %end; %if &printop >= 4 and &printop <= 6 and &points = %then %do; %put ERROR - Variable = 4,5,6, but missing; %LET errorflg = 1; %end; %if &plottype<1 or &plottype>4 %then %do; %put ERROR - Variable not 1,2,3, or 4; %LET errorflg = 1; %end; %if &plotop<1 or &plotop>2 %then %do; %put ERROR - Variable not 1 or 2; %LET errorflg = 1; %end; %if &scale<1 or &scale>3 %then %do; %put ERROR - Variable not 1, 2, or 3; %LET errorflg = 1; %end; %if &laserprt^= and &plottype^=3 %then %do; %put ERROR - Variable is present, but = 3, but running on an IBM machine; %LET errorflg = 1; %end; %if &plottype=4 and &sysenv=BACK %then %do; %put ERROR - Variable = 4, but running in backgroupd; %LET errorflg = 1; %end; %if &medtype<1 or &medtype>2 %then %do; %put ERROR - Variable is not 1 or 2; %let errorflg = 1; %end; %if &cl<1 or &cl>8 %then %do; %put ERROR - Variable is not 1-8; %let errorflg = 1; %end; %if &errorflg = 1 %then %do; data _null_; error 'ERROR - detected in the input data to the macro .'; %go to exit; %end; %IF &BY^= %THEN %DO; %LET byword=BY; %LET byclword=BY; %DO J=1 %TO 50 %BY 1; /* find last BY variable */ %LET X=%SCAN(&BY,&J); %IF &X^= %THEN %do; %LET lastby=&X; %LET lastbycl=&X; %end; %ELSE %GOTO NEXT1; %END; %NEXT1: %END; %IF &CLASS^= %THEN %DO; %LET byclword=BY; %DO J=1 %TO 50 %BY 1; /* find last CLASS variable */ %LET X=%SCAN(&CLASS,&J); %IF &X^= %THEN %do; %LET lastbycl=&X; %let V&j = &X; %let cgrp = &j; %local V&j; %end; %ELSE %GOTO NEXT2; %END; %NEXT2: %END; data _tmp_; set &data; keep &by &class &strttime &stoptime &event; %if &class^= %then %do; %do j=1 %to &cgrp %by 1; where &&v&j is not missing; %end; %end; if &strttime=. or &strttime < 0 then do; error "ERROR - &strttime= " &strttime ' - not used.'; &strttime = .; &stoptime = .; &event = .; end; %if &stoptime^= %then %do; if &stoptime=. or &stoptime < 0 then do; error "ERROR - &stoptime= " &stoptime ' - not used.'; &stoptime = .; &strttime = .; &event = .; end; if &strttime>=&stoptime then do; error "ERROR - &strttime>=&stoptime " ' - not used.'; &strttime = .; &stoptime = .; &event = .; end; if &event > &cen_vl+1 or &event < &cen_vl then do; error "ERROR - &event= " &event ' - not used.'; &strttime = .; &stoptime = .; &event = .; end; %end; PROC SORT data=_tmp_; BY &by &class &stoptime ; PROC MEANS NOPRINT DATA=_TMP_; VAR &stoptime ; &byclword &by &class; OUTPUT OUT=_COUNTS_ N=nrisk max=maxtime nmiss=tl_miss; data _arrive_; set _tmp_; keep &by &class &stoptime arrival; &stoptime=&strttime; arrival=1; data _tmp_; set _tmp_ _arrive_; proc sort; by &by &class &stoptime; %IF &POINTS^= %THEN %DO; data _TMP1_; /* add point observations */ set _COUNTS_; keep &by &class &stoptime &event point narr; flag=0; do j=&points; if flag=1 then return; if j>=maxtime then flag=1; if j>0 then do; &stoptime = j; &event = .; point = 1; output; end; end; data _TMP_; set _TMP_ _TMP1_; proc sort; by &BY &CLASS &stoptime ; %END; DATA &OUT (KEEP=&by &CLASS &stoptime nrisk nevent ncensor narrive cum_ev cum_cen cum_arr pt pe upper_cl lower_cl se pointflg) &outsum (keep=&by &class total cum_ev cum_cen cum_arr median tl_miss) _print_ (keep=&by &class &stoptime years nrisk nevent pt ncensor narrive lower_cl upper_cl se cum_ev cum_cen cum_arr); SET _TMP_ nobs=nobs; BY &by &class &stoptime ; RETAIN pt nevent _kt_ ncensor nrisk narrive _sv1_ cum_ev cum_cen total median firstmed pointflg laster loweradj cum_arr oldpt; LABEL pt="Kaplan-Meier Survival Estimate" pe = "1-P(t)" se="Greenwold Standard Error" lower_cl ="Lower Confidence Limit" upper_cl ="Upper Confidence Limit" NRISK="Number at Risk at beginning of (t)" NEVENT="Number of Events at (t)" ncensor="Number Censored at (t)" narrive="Number of Arrivals at (t)" cum_ev = "Cumulative events including (t)" cum_cen = "Cumulative censors including (t)" cum_arr = "Cumulative arrivals including (t)" median = "Median Survival" tl_miss = "Total Missing" pointflg = "Added Times" ; _FT_=FIRST. &stoptime ; _LT_=LAST. &stoptime ; %if &points = %then %do; point=.; %end; %IF &lastbycl^= %THEN %DO; IF FIRST.&lastbycl=0 THEN GO TO NOTFIRST; %END; %ELSE %DO; IF _N_>1 THEN GO TO NOTFIRST; %END; /* do if the first observation per by group */ SET _COUNTS_; /* read observation from _counts_ */ total = nrisk; nrisk=0; _thold_= &stoptime; laster=nrisk; pointflg=.; &stoptime =0; nevent=0; _kt_=0; ncensor=0; narrive=0; cum_ev=0; cum_cen=0; cum_arr=0; pt=1; oldpt = pt; pe=0; se=0; _sv1_=0; lower_cl=1; upper_cl=1; loweradj=.; years=0; OUTPUT &out; /* output an observation at time=0 */ OUTPUT _print_; &stoptime =_THOLD_; median=.; firstmed=.; /* do for each observation in the dataset */ NOTFIRST: IF _FT_ then do; /* do for the first obs. per time */ nevent=0; _kt_=0; ncensor=0; narrive=0; pointflg=.; end; /* for each observation */ if point = 1 then pointflg = 1; if point ^= 1 and arrival^=1 and &stoptime ^= . then do; if &event = &cen_vl+1 then NEVENT=NEVENT+1; else ncensor=ncensor+1; _KT_=_KT_+1; end; if arrival=1 then narrive = narrive + 1; IF _LT_ then do; /* do for the last observation per time */ if _kt_ = 0 and pointflg ^= 1 and narrive=0 then go to next3; /* if time< mintime */ if &stoptime < &mintime then go to next3; if nrisk>0 then pt=pt*(1-NEVENT/NRISK); else pt=oldpt; oldpt = pt; pe = 1 - pt; cum_ev = cum_ev + nevent; cum_cen = cum_cen + ncensor; cum_arr = cum_arr + narrive; if nevent>0 then laster=nrisk; /* nrisk at last event time */ IF nrisk<=nevent THEN DO; se=.; lower_cl=.; upper_cl=.; END; ELSE DO; if _kt_>0 then loweradj=SQRT(laster/nrisk); _sv1_=_sv1_+nevent/nrisk/(nrisk-nevent); se=SQRT(pt*pt*_sv1_); %if &cl=1 %then %do; %let cl_name=Greenwood; lower_cl=pt-PROBIT(1-&alpha/2)*se; upper_cl=pt+PROBIT(1-&alpha/2)*se; %end; %if &cl=2 %then %do; %let cl_name=Green(adj); lower_cl=pt-PROBIT(1-&alpha/2)*loweradj*se; upper_cl=pt+PROBIT(1-&alpha/2)*se; %end; %if &cl=3 %then %do; %let cl_name=Log; _w_=PROBIT(1-&alpha/2)*sqrt(_sv1_); lower_cl=exp(log(pt)-_w_); upper_cl=exp(log(pt)+_w_); %end; %if &cl=4 %then %do; %let cl_name=Log(adj); _wl_=PROBIT(1-&alpha/2)*loweradj*sqrt(_sv1_); _w_=PROBIT(1-&alpha/2)*sqrt(_sv1_); lower_cl=exp(log(pt)-_wl_); upper_cl=exp(log(pt)+_w_); %end; %if &cl=5 %then %do; %let cl_name=Log(-log); if pt^=1 then do; _w_=PROBIT(1-&alpha/2)*sqrt(_sv1_)/log(pt); lower_cl=pt**exp(-_w_); upper_cl=pt**exp(_w_); end; else do; lower_cl=1; upper_cl=1; end; %end; %if &cl=6 %then %do; %let cl_name=Log(-log)adj; if pt^=1 then do; _wl_=PROBIT(1-&alpha/2)*loweradj*sqrt(_sv1_)/log(pt); _w_=PROBIT(1-&alpha/2)*sqrt(_sv1_)/log(pt); lower_cl=pt**exp(-_wl_); upper_cl=pt**exp(_w_); end; else do; lower_cl=1; upper_cl=1; end; %end; %if &cl=7 %then %do; %let cl_name=Logit; if pt^=1 then do; _w_=PROBIT(1-&alpha/2)*sqrt(_sv1_/(1-pt)**2); _zl_=exp(log(pt/(1-pt))-_w_); _zu_=exp(log(pt/(1-pt))+_w_); lower_cl=_zl_/(1+_zl_); upper_cl=_zu_/(1+_zu_); end; else do; lower_cl=1; upper_cl=1; end; %end; %if &cl=8 %then %do; %let cl_name=Logit(adj); if pt^=1 then do; _w_=PROBIT(1-&alpha/2)*sqrt(_sv1_/(1-pt)**2); _wl_=PROBIT(1-&alpha/2)*loweradj*sqrt(_sv1_/(1-pt)**2); _zl_=exp(log(pt/(1-pt))-_wl_); _zu_=exp(log(pt/(1-pt))+_w_); lower_cl=_zl_/(1+_zl_); upper_cl=_zu_/(1+_zu_); end; else do; lower_cl=1; upper_cl=1; end; %end; if lower_cl<0 then lower_cl=0; if upper_cl>1 then upper_cl=1; END; OUTPUT &out; years = round( &stoptime /365,0.01); %if &printop = 2 %then %do; if nevent > 0 then output _print_; %end; %if &printop = 3 %then %do; if nevent > 0 or ncensor > 0 or narrive > 0 then output _print_; %end; %if &printop = 4 %then %do; if pointflg = 1 then output _print_; if &stoptime =0 and (nevent>0 or ncensor>0) then output _print_; %end; %if &printop = 5 %then %do; if nevent > 0 or pointflg = 1 then output _print_; %end; %if &printop = 6 %then %do; output _print_; %end; next3: NRISK=NRISK-_KT_; nrisk=nrisk+narrive; if _kt_ = 0 or pt=. or &stoptime<&mintime then go to next4; if ABS(pt-0.5)<=0.00001 then do; if firstmed = . then firstmed = &stoptime ; end; if median=. and round(pt,0.00001) < 0.5 THEN DO; if firstmed ^=. then %if &medtype=1 %then %do; median = ( &stoptime + firstmed)/2.0; %end; %if &medtype=2 %then %do; median = firstmed; %end; else median = &stoptime ; end; next4: /* output summary data */ %IF &lastbycl^= %THEN %DO; IF LAST.&lastbycl=1 THEN output &outsum; %END; %ELSE %DO; IF _N_=nobs THEN output &outsum; %END; end; run; %if &printop = 0 %then %goto plots; proc print data=&outsum split='*'; &byword &by; id &class; var total cum_ev cum_cen cum_arr tl_miss median; label total = Total*N tl_miss = Total*Missing cum_ev = Total*Events cum_cen = Total*Censors cum_arr = Total*Arrivals median = Median*Survival ; sum total cum_ev cum_cen tl_miss; title&t "Survival Summary Table for Variables < &stoptime > and <&event>"; title&u "With Arrivals - Calculations starting at t(&mintime)"; footnote1 "Input Parameters (STRTTIME=&strttime,STOPTIME=&stoptime," "EVENT=&event,CEN_VL=&cen_vl," "PRINTOP=&printop,CLASS=&class,BY=&by,"; footnote2 "DATA=&data,OUT=&out," " POINTS=&points,CL=&cl,ALPHA=&alpha,"; footnote3 "PLOTTYPE=&plottype,PLOTOP=&plotop,SCALE=&scale,MAXTIME=" "&maxtime,XDIVISOR=&xdivisor,LASERPRT=&laserprt," "MEDTYPE=&medtype,OUTSUM=&outsum,MINTIME=&mintime)"; run; %if &printop = 1 %then %goto plots; data _NUll_; y=put(100-&alpha*100,2.); call symput('percent',y); footnote1; footnote2; footnote3; proc print data=_print_ split='*'; &byclword &by &class; id &stoptime years; %if &printop = 2 %then %do; var nrisk nevent pt lower_cl upper_cl se; sum nevent; %end; %if &printop = 3 %then %do; var nrisk narrive nevent ncensor pt lower_cl upper_cl se; sum narrive nevent ncensor; %end; %if &printop = 4 %then %do; var nrisk cum_arr cum_ev cum_cen pt lower_cl upper_cl se; %end; %if &printop = 5 %then %do; var nrisk nevent pt lower_cl upper_cl se; sum nevent; %end; %if &printop = 6 %then %do; var nrisk narrive nevent ncensor pt lower_cl upper_cl se; sum narrive nevent ncensor; %end; format pt lower_cl upper_cl se 5.3; label &stoptime = * &stoptime *(t) years = * &stoptime *'/365' nrisk = Number*'at Risk'*'at (t)' cum_ev = Cumulative*'# Events'*'<= (t)' narrive = Number*'Arrivals'*'at (t)' cum_arr = Cumulative*'# Arrivals'*'<= (t)' nevent = Number*'Events'*'at (t)' ncensor = Number*'Censors'*'at (t)' cum_cen = Cumulative*'# Censors'*'<= (t)' pt = Probability*'No Event'*'<= (t)' lower_cl = "Lower &percent%"*'C. Limit'*"(&cl_name)" upper_cl = "Upper &percent%"*'C. Limit'*"(&cl_name)" se = Greenwood*Standard*Error; %if &by ^= %then %do; pageby &lastby; %end; title&t "Kaplan-Meier Survival Estimates for < &stoptime > and <&event>"; title&u "With Arrivals - Calculations starting at t(&mintime)"; run; /* plotting */ %plots: title&t; title&u; %if &plottype=1 %then %goto exit; %if &plottype=2 %then %do; %LET indata = &out; PROC MEANS NOPRINT DATA=_counts_; &byword &by; VAR maxtime; OUTPUT OUT=_MAX_ max=maxt; %if &maxtime ^= %then %do; data _max_; set _max_; if maxt>&maxtime then maxt=&maxtime; %end; %if &xdivisor ^= %then %do; data _max_; set _max_; maxt=maxt/&xdivisor; data _tmp_; set &out; &stoptime = &stoptime /&xdivisor; %let indata = _tmp_; %end; data _tmp_; set &indata; &byword &by; keep &by x y symbol; retain maxt xtick ytick oldx oldy; if pt=. then delete; label x = " &stoptime "; label y = 'Percent'; %if &xdivisor ^= %then %do; label x = " &stoptime /&xdivisor"; %end; %if &class ^= %then %do; symbol=&class; label symbol = "&class"; %end; %else %do; symbol='*'; %end; %IF &lastby^= %THEN %DO; IF FIRST.&lastby=0 THEN GO TO next4; %END; %ELSE %DO; IF _N_>1 THEN GO TO next4; %END; SET _Max_; xtick=maxt/100/2; ytick=1/30/2; %if &sysscp=OS %then %do; ytick=1/40/2; %end; oldx=.; oldy=.; pt=pt*100; go to next5; next4: pt=pt*100; if oldx ^=. and oldx > &stoptime then do; /* first obs for next class */ oldx=.; oldy=.; go to next5; end; if &stoptime >0 and nevent=0 and ncensor=0 then return; /* horizonal dots */ do i=oldx to &stoptime -xtick by xtick while (i<=maxt); if i^=oldx then do; x=i; y=oldy; output; end; end; if oldy^=pt and &stoptime <=maxt then do i=oldy to pt by -ytick; x= &stoptime ; y=i; output; end; next5: x= &stoptime ; y=pt; if x<=maxt then output; oldx=x; oldy=y; %if &plotop = 2 %then %do; data _tmp_; set _tmp_; y=100-y; %end; proc plot data=_tmp_ nolegend uniform; &byword &by; plot y*x=symbol /hzero hpos=100 %if &sysscp=OS %then %do; vpos=40 %end; %else %do; vpos=30 %end; %if &scale=1 %then %do; vaxis=0 to 100 by 25; %end; %if &scale=2 %then %do; vaxis=10 17.78 31.62 56.233 100; %end; %if &scale=3 %then %do; vaxis=1 3.162 10 31.62 100; %end; footnote1 "TIME= &stoptime, EVENT=&event, CLASS=&class - " "With Arrivals - Calculations starting at t(&mintime)"; run; %end; %if &plottype = 3 %then %do; %if &laserprt ^= %then %do; filename graphout pipe "cat | /usr/ucb/lpr -P&laserprt "; %end; %else %do; filename graphout pipe 'cat | /usr/ucb/lpr '; %end; /* libname gdevice0 '/people/statsys/kosanke/mydevices'; */ goptions cback=white colors=(black) device=apple; %end; %if &plottype >= 3 %then %do; data _tmp_; set &out; keep x y &class &by; retain lastpt lastx; label y = 'Percent'; if &stoptime =0 then do; lastx=.; lastpt=.; end; if &stoptime >0 and nevent=0 and ncensor=0 then delete; %if &maxtime^= %then %do; if &stoptime >&maxtime then do; if lastx=1 then delete; else do; lastx=1; &stoptime =&maxtime; pt=lastpt; end; end; %end; lastpt=pt; y=pt*100; %if &plotop = 2 %then %do; y=100-y; %end; %if &xdivisor ^= %then %do; label x = " &stoptime /&xdivisor"; x = &stoptime /&xdivisor; %end; %else %do; label x = " &stoptime "; x= &stoptime ; %end; proc gplot data=_tmp_; &byword &by; %if &class ^= %then %do; plot y*x=&class %end; %else %do; plot y*x %end; /hzero %if &scale=1 %then %do; vaxis=0 to 100 by 10; %end; %if &scale=2 %then %do; vaxis=10 17.78 31.62 56.233 100; %end; %if &scale=3 %then %do; vaxis=1 3.162 10 31.62 100; %end; symbol1 i=stepjl v=none l=1; symbol2 i=stepjl v=none l=2; symbol3 i=stepjl v=none l=4; symbol4 i=stepjl v=none l=8; symbol5 i=stepjl v=none l=41; symbol6 i=stepjl v=none l=33; symbol7 i=stepjl v=none l=35; symbol8 i=stepjl v=none l=46; symbol9 i=stepjl v=none l=40; footnote1 "TIME= &stoptime, EVENT=&event, CLASS=&class - " "With Arrivals - Calculations starting at t(&mintime)"; run; %end; proc datasets nolist; %if &points ^= %then %do; delete _tmp1_ _tmp_ _counts_ _print_; %end; %else %do; delete _tmp_ _counts_ _print_; %end; run; quit; footnote1; %exit: OPTIONS _LAST_=&out; %let SYSDEVIC = &dev; %MEND SURVTD;